/**
 * @Author: Jiang Zhongxun
 * @Date: 2025-01-15 16:06:14
 * @FilePath: \ESP32_Smart_Lock\main\drivers\OTA_Driver.c
 * @Description: OTA 在线升级
 * @Copyright (c) 2025 by JiangZhongxun, All Rights Reserved.
 */
#include "OTA_Driver.h"
#include "AUDIO_Driver.h"

// ###########################################################【以下代码来自示例代码】###############################################################################
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "esp_event.h"
#include "esp_log.h"
#include "esp_ota_ops.h"
#include "esp_http_client.h"
#include "esp_https_ota.h"
#include "string.h"
#include "esp_crt_bundle.h"
#include "esp_wifi.h"
#include "esp_netif.h"

#define HASH_LEN 32
#define OTA_URL_SIZE 256
#define EXAMPLE_NETIF_DESC_STA "example_netif_sta"

// static const char *bind_interface_name = EXAMPLE_NETIF_DESC_STA;
static const char *TAG = "OTA 任务: ";
// ###########################################################【以上代码来自示例代码】###############################################################################

// ###########################################################【以下代码来自示例代码】###############################################################################
esp_netif_t *get_example_netif_from_desc(const char *desc)
{
    esp_netif_t *netif = NULL;
    while ((netif = esp_netif_next_unsafe(netif)) != NULL)
    {
        if (strcmp(esp_netif_get_desc(netif), desc) == 0)
        {
            return netif;
        }
    }
    return netif;
}

/**
 * @description: sha256 是一种加密算法，类似于 md5, 将输入转换成 256 个 bit 的数值, sha512, sha128
 * @param {uint8_t} *image_hash
 * @param {char} *label
 * @return {*}
 */
static void print_sha256(const uint8_t *image_hash, const char *label)
{
    char hash_print[HASH_LEN * 2 + 1];
    hash_print[HASH_LEN * 2] = 0;
    for (int i = 0; i < HASH_LEN; ++i)
    {
        sprintf(&hash_print[i * 2], "%02x", image_hash[i]);
    }
    ESP_LOGI(TAG, "%s %s", label, hash_print);
}

/**
 * @description: 获取分区的 sha256 值
 * @param {*}
 * @return {*}
 */
void get_sha256_of_partitions(void)
{
    uint8_t sha_256[HASH_LEN] = {0};
    esp_partition_t partition;

    // get sha256 digest for bootloader
    partition.address = ESP_BOOTLOADER_OFFSET;
    partition.size = ESP_PARTITION_TABLE_OFFSET;
    partition.type = ESP_PARTITION_TYPE_APP;
    esp_partition_get_sha256(&partition, sha_256);
    print_sha256(sha_256, "SHA-256 for bootloader: ");

    // get sha256 digest for running partition
    esp_partition_get_sha256(esp_ota_get_running_partition(), sha_256);
    print_sha256(sha_256, "SHA-256 for current firmware: ");
}

/**
 * @description: 处理一系列的 HTTP 事件
 * @param {esp_http_client_event_t} *evt
 * @return {*}
 */
esp_err_t _http_event_handler(esp_http_client_event_t *evt)
{
    switch (evt->event_id)
    {
    case HTTP_EVENT_ERROR:
        ESP_LOGD(TAG, "HTTP_EVENT_ERROR");
        break;
    case HTTP_EVENT_ON_CONNECTED:
        ESP_LOGD(TAG, "HTTP_EVENT_ON_CONNECTED");
        break;
    case HTTP_EVENT_HEADER_SENT:
        ESP_LOGD(TAG, "HTTP_EVENT_HEADER_SENT");
        break;
    case HTTP_EVENT_ON_HEADER:
        ESP_LOGD(TAG, "HTTP_EVENT_ON_HEADER, key=%s, value=%s", evt->header_key, evt->header_value);
        break;
    case HTTP_EVENT_ON_DATA:
        ESP_LOGD(TAG, "HTTP_EVENT_ON_DATA, len=%d", evt->data_len);
        break;
    case HTTP_EVENT_ON_FINISH:
        ESP_LOGD(TAG, "HTTP_EVENT_ON_FINISH");
        break;
    case HTTP_EVENT_DISCONNECTED:
        ESP_LOGD(TAG, "HTTP_EVENT_DISCONNECTED");
        break;
    case HTTP_EVENT_REDIRECT:
        ESP_LOGD(TAG, "HTTP_EVENT_REDIRECT");
        break;
    }
    return ESP_OK;
}
// ###########################################################【以上代码来自示例代码】###############################################################################

/**
 * @description: 启动 OTA 在线升级
 * @param {*} 无参
 * @return {*} 无返回值
 */
void OAT_Start(void)
{
    // 计算每个 flash 分区的 sha256 数字签名
    get_sha256_of_partitions();
    ESP_LOGI(TAG, "OTA任务开始了 ......\r\n");
    // ota 相关配置
    esp_http_client_config_t config = {
        // .url = "http://172.20.10.6:8088/led_strip.bin", // 固件下载地址
        .url = "http://172.20.10.6:8088/ESP32_Smart_Lock.bin", // 固件下载地址
        .crt_bundle_attach = esp_crt_bundle_attach,            // 加密相关
        .event_handler = _http_event_handler,                  // 注册处理 HTTP 事件的回调函数
        .keep_alive_enable = true,                             // 保持活跃连接
    };

    esp_https_ota_config_t ota_config = {
        .http_config = &config,
    };

    ESP_LOGI(TAG, "Attempting to download update from %s", config.url);

    // 开始下载远程的二进制文件
    esp_err_t ret = esp_https_ota(&ota_config);
    // 下载完成
    if (ret == ESP_OK)
    {
        // 操作成功
        AUDIO_Play(46);
        vTaskDelay(100 / portTICK_PERIOD_MS);
        ESP_LOGI(TAG, "OTA Success, Rebooting ......\r\n");
        // 重启 ESP32 开发板
        esp_restart();
    }
    else
    {
        // 操作失败
        AUDIO_Play(47);
        ESP_LOGI(TAG, "Firmware Upgrade Faile ......\r\n");
    }
}
